package fr.imag.ufrima.ima.project.core;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.Arrays;

import javax.swing.JPanel;

import org.apache.log4j.Logger;

public class Histogram extends JPanel {
	private Logger logger = Logger.getLogger(getClass().getName());

	private BufferedImage histogramImage;
	private int[] histogram;
	private float[] normalizedHistogram;
	private Color color;
	private int oldMeanValue;
	private int dif;

	public void createFromBufferedImage(BufferedImage histogramImage, Color c) {

		color = c;
		this.histogramImage = histogramImage;

		this.build();
		this.normalize();
	}

	public void createFromArray(int[] histogram, Color c) {

		color = c;
		this.histogram = histogram;
		this.normalize();
	}

	private void build() {

		histogram = new int[256];
		// calcule de tabs
		if (color.equals(Color.RED)) {
			for (int j = 0; j < histogramImage.getHeight(); j++) {
				for (int i = 0; i < histogramImage.getWidth(); i++) {
					int rgb = histogramImage.getRGB(i, j);
					histogram[((rgb >> 16) & 0xFF)]++; // rouge
				}
			}
		} else if (color.equals(Color.GREEN)) {
			for (int j = 0; j < histogramImage.getHeight(); j++) {
				for (int i = 0; i < histogramImage.getWidth(); i++) {
					int rgb = histogramImage.getRGB(i, j);
					histogram[((rgb >> 8) & 0xFF)]++; // vert
				}
			}
		} else if (color.equals(Color.BLUE)) {
			for (int j = 0; j < histogramImage.getHeight(); j++) {
				for (int i = 0; i < histogramImage.getWidth(); i++) {
					int rgb = histogramImage.getRGB(i, j);
					histogram[(rgb & 0xFF)]++; // bleu
				}
			}
		}

	}

	private void normalize() {
		logger.debug(String.format("About to normalize histogram: %s", Arrays.toString(histogram)));

		normalizedHistogram = new float[histogram.length];
		float maxValue = 0;
		for (int i = 0; i < histogram.length; i++) {
			if (histogram[i] > maxValue) {
				maxValue = histogram[i];
			}
		}
		for (int i = 0; i < histogram.length; i++) {
			normalizedHistogram[i] = (float) histogram[i] / maxValue;
		}

		logger.debug(String.format("Normalized histogram: maxValue %f, data: %s", maxValue,
				Arrays.toString(normalizedHistogram)));
	}

	@Override
	public void paint(Graphics graphics) {
		// TODO Auto-generated method stub
		super.paint(graphics);

		if (histogram != null) {
			Graphics2D g = (Graphics2D) graphics;
			g.setColor(color);

			float deltaX = this.getWidth() / (float) normalizedHistogram.length;
			float deltaY = this.getHeight();
			for (int i = 0; i < normalizedHistogram.length; i++) {

				float x = (deltaX * i);
				float y = (deltaY - (deltaY * normalizedHistogram[i]));
				float w = deltaX * 2;
				float h = (deltaY * normalizedHistogram[i]) - 2;

				g.fillRect((int) x, (int) y, (int) w, (int) h);
				
				//logger.debug(String.format("Drawing histogram bar: %f %f %f %f", x, y, w, h));
			}
		}
	}

	public int getHistogramMean() // calcule moyenne de couleur d'un histo..
	// deuxieme moitier du tab
	{
		int[] tab = this.histogram;
		int m = 0;
		for (int i = tab.length / 2; i < tab.length; i++) {
			m += tab[i];
		}
		m /= tab.length;
		if (m > 255)
			m = 255;

		oldMeanValue = m;
		logger.debug(String.format("The original mean is: %d", oldMeanValue));
		return m;
	}

	public int[] changeHistogramMean(int nval) {
		int[] tab = this.histogram;
		
		int aval = oldMeanValue;
		dif = nval - aval;
		if (dif > 0) // si augmentation de moyenne
		{
			System.out.println("augmentation");

			for (int i = 0; i < tab.length / 2; i++) // premiere moitier --
			{
				if (tab[i] - dif >= 0)
					tab[i] -= dif;
				else
					tab[i] = 0;
			}

			for (int i = tab.length / 2; i < tab.length; i++) // deuxieme
			// moitier ++
			{
				tab[i] += dif;
			}
		}

		if (dif < 0) {
			System.out.println("diminuation"); // si diminuation demoyenne
			for (int i = 0; i < tab.length / 2; i++) // premiere moitier ++
			{
				tab[i] -= dif;
			}
			for (int i = tab.length / 2; i < tab.length; i++) // deuxieme
			// moitier --
			{
				if (tab[i] + dif > 0)
					tab[i] += dif;
				else
					tab[i] = 0;
			}
		}
		oldMeanValue = nval;
		return tab;
	}

//////////////////////////////////////////////////////////////////////////////////////////
	public int[] regalize() {
		int[] tab = this.histogram;
		int max=0,indmax=0; 	//val maximale du tab
		
		for(int i=0;i<tab.length;i++){
			if(max<tab[i]){
				max=tab[i];
				indmax=i;
			}
		}
		
		for(int i=indmax;i<tab.length;i++){	//cot� droite
			if(tab[indmax]-10>tab[i]+10){
				tab[indmax]-=10;
				tab[i]+=10;
			}	
		}
		
		//int i=indmax;
		for(int i=indmax;i>0;i--){	//cot� gauche
			
			if(tab[indmax]-10>tab[i]+10){
				tab[indmax]-=10;
				tab[i]+=10;
			}
		}
		return tab;
	}
//////////////////////////////////////////////////////////////////////////////////////////

	public BufferedImage modifImagByHisto(Image originalImage) {
		int[][][] tab = originalImage.getTab();

		int val;
		int w = originalImage.getWidth();
		int h = originalImage.getHeight();
		BufferedImage modifiedHistogramImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);

		if (this.color == Color.RED)// si changement du rouge
		{
			for (int j = 0; j < h; j++) {
				for (int i = 0; i < w; i++) {
					int pval1, pval2, pval3, pval0; // operation intiale
					pval0 = (tab[i][j][0]);
					
					pval1 = (tab[i][j][1] + this.dif);
					pval2 = (tab[i][j][2] - this.dif/2);
					pval3 = (tab[i][j][3] - this.dif/2);
					if(pval1>255)
						pval1=255;
					if(pval1<0)
						pval1=0;
					if(pval2>255)
						pval2=255;
					if(pval2<0)
						pval2=0;
					if(pval3>255)
						pval3=255;
					if(pval3<0)
						pval3=0;
					val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
					modifiedHistogramImage.setRGB(i, j, val);
				}
			}
		} else if (this.color == Color.GREEN)// si changement du vert
		{
			for (int j = 0; j < h; j++) {
				for (int i = 0; i < w; i++) {
					int pval1, pval2, pval3, pval0; // operation intiale
					pval0 = (tab[i][j][0]);
					pval1 = (tab[i][j][1] - this.dif/2);
					pval2 = (tab[i][j][2] + this.dif);
					pval3 = (tab[i][j][3] - this.dif/2);
					if(pval1>255)
						pval1=255;
					if(pval1<0)
						pval1=0;
					if(pval2>255)
						pval2=255;
					if(pval2<0)
						pval2=0;
					if(pval3>255)
						pval3=255;
					if(pval3<0)
						pval3=0;
					val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
					modifiedHistogramImage.setRGB(i, j, val);
				}
			}
		} else if (this.color == Color.BLUE)// si changement du bleu
		{
			for (int j = 0; j < h; j++) {
				for (int i = 0; i < w; i++) {
					int pval1, pval2, pval3, pval0; // operation intiale
					pval0 = (tab[i][j][0]);
					pval1 = (tab[i][j][1] - this.dif/2);
					pval2 = (tab[i][j][2] - this.dif/2);
					pval3 = (tab[i][j][3] + this.dif);
					if(pval1>255)
						pval1=255;
					if(pval1<0)
						pval1=0;
					if(pval2>255)
						pval2=255;
					if(pval2<0)
						pval2=0;
					if(pval3>255)
						pval3=255;
					if(pval3<0)
						pval3=0;
					val = (pval0 << 24) + (pval1 << 16) + (pval2 << 8) + (pval3);
					modifiedHistogramImage.setRGB(i, j, val);
				}
			}
		}
		return modifiedHistogramImage;
	}

	public int[] getHistogram() {
		return histogram;
	}

	public Color getColor() {
		return color;
	}
}